package com.ruicar.afs.cloud.batch.frame;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.ruicar.afs.cloud.batch.config.JdbcConfig;
import com.ruicar.afs.cloud.batch.frame.bean.BatchDateInfo;
import com.ruicar.afs.cloud.batch.frame.bean.BatchResourceHolder;
import com.ruicar.afs.cloud.batch.frame.control.BatchControlRunner;
import com.ruicar.afs.cloud.batch.frame.control.MonitorControl;
import com.ruicar.afs.cloud.batch.service.AfsBatchInfoService;
import com.ruicar.afs.cloud.batch.service.AfsBatchJobStepBreakPointService;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;

public abstract class AbsBatchRunner extends BatchControlRunner implements BatchRunner {

    protected Logger logger = LoggerFactory.getLogger(this.getClass().getName());
    private List<Connection> connectionList = new ArrayList<>();
    @Setter
    protected BatchDateInfo batchDateInfo;
    @Setter
    private Lock shareLock;
    @Setter
    @Getter
    private String systemName ;
    @Setter
    @Getter
    private String batchNo ;
    @Setter
    @Getter
    private String stepNo ;
    @Setter
    private String stepName ;
    @Setter
    private int threadNum;
    @Setter
    private CountDownLatch countDownLatch;
    @Setter
    private String params;

    @Setter
    private MonitorControl monitorControl;

    protected Connection getConnection(String databaseName){

        if(!BatchResourceHolder.jdbcList.containsKey(databaseName)){
            throw new AfsBaseException("数据库"+databaseName+"连接不存在");
        }
        try {
            JdbcConfig jdbcConfig = BatchResourceHolder.jdbcList.get(databaseName);
            Class.forName(jdbcConfig.getDriverClassName());
            Connection connection = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUsername(), jdbcConfig.getPassword());
            connection.setAutoCommit(false);
            connectionList.add(connection);
            return connection;
        }catch (Exception e){
            logger.error("",e);
            throw new AfsBaseException("获取连接出错");
        }
    }

    protected Connection getConnection(){
        return getConnection(CommonConstants.DEFAULT);
    }

    @Override
    public void saveBreakPoint(String breakPoint) {
        try{
            shareLock.lock();
            SpringContextHolder.getBean(AfsBatchJobStepBreakPointService.class).saveBreakPoint(systemName,batchNo,stepNo,batchDateInfo.getBatchStringDate(),breakPoint);
        }finally {
            shareLock.unlock();
        }
    }

    @Override
    public String loadBreakPoint() {
        try {
            shareLock.lock();
            return SpringContextHolder.getBean(AfsBatchJobStepBreakPointService.class).loadBreakPoint(systemName, batchNo, stepNo, batchDateInfo.getBatchStringDate());
        }finally {
            shareLock.unlock();
        }
    }
    @Override
    public void run() {
        try {
            monitorControl.add(this);
            process(params);
        }catch (Throwable e){
            connectionList.forEach(this::rollBack);
            logger.error("步骤执行出错",e);
            Throwable interruptedException = ExceptionUtil.getCausedBy(e, InterruptedException.class);
            if(interruptedException!=null){
                this.setThrowable(interruptedException);
            }else{
                this.setThrowable(e);
            }
            throw e;
        }finally {
            connectionList.forEach(this::clean);
            if(countDownLatch!=null) {
                SpringContextHolder.getBean(AfsBatchInfoService.class).cutDown(getSystemName(),1,MessageFormat.format("StepRunner-{0}-{1}-{2}",systemName,batchNo,stepNo));
                countDownLatch.countDown();
            }
            this.setFinished();
            this.setSelfFinished(true);
            this.setSubFinished(true);
        }
    }
}
